package com.utility.project.config;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;

import com.utility.project.annotation.Limit;
import com.utility.project.common.base.R;
import com.utility.project.common.constants.HttpCodeEnum;
import com.utility.project.common.utils.HttpHelper;
import com.utility.project.common.utils.SignatureUtil;
import com.utility.project.common.utils.SlideWindowLimitUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

/**
 * 对外开放平台拦截器处理
 *
 * @author nari-yzg
 * @return
 * @date 2021/3/30 10:44
 */
@Configuration
public class DataAuthInterceptor implements AsyncHandlerInterceptor {


    private Logger log = LoggerFactory.getLogger(DataAuthInterceptor.class);

    /**
     * ControllerController逻辑执行之前
     *
     * @return
     * @author nari-yzg
     * @date 2021/3/30 10:48
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        String uri = request.getRequestURI();
        //获取app编码
        String appCode = request.getHeader("appCode");
        //获取app编码
        String appSignature = request.getHeader("appSignature");
        //获取签名摘要
        String payload = HttpHelper.getBodyString(request);
        //获取随机数
        Integer random = 0;
        if (StrUtil.isNotBlank(request.getHeader("random"))) {
            random = Integer.parseInt(request.getHeader("random"));
        }
        //获取时间戳
        String timestamp = request.getHeader("timestamp");
        log.info("request uri：" + uri);
        //如果appCode和采用同样加密算法的签名为空，则直接返回错误信息
        if (StrUtil.isBlank(appCode) || StrUtil.isBlank(appSignature)) {
            unAuthorized(request, response);
        } else {
            if (handler instanceof HandlerMethod) {
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                log.info("拦截 Controller：" + handlerMethod.getBean().getClass().getName() + ",拦截方法：" + handlerMethod.getMethod().getName());
                //针对接口请求限流处理
                Limit limitMethod = handlerMethod.getMethodAnnotation(Limit.class);
                if (limitMethod != null) {
                    if (!checkLimit(limitMethod)) {
                        String error = JSONObject.toJSONString(R.fail(HttpCodeEnum.NOT_ACCEPTABLE.getCode(),HttpCodeEnum.NOT_ACCEPTABLE.getMessage()));
                        log.error("request uri = {}, request too many times", request.getRequestURI());
                        this.setHttpResponse(response, error);
                    }
                }
                //获取appSecret
                String appSecret = "0fa3b30b-7309-4319-a15b-82d51a47654b";
                //采用网易sha加密算法摘要生成appSignature，然后与前端传过来的appSignature比对
                String generateSignature = SignatureUtil.generateSignature(appCode, appSecret, payload, random, timestamp);
                boolean res = generateSignature.equals(appSignature);
                //比对失败，则返回错误认证信息
                if (res == false) {
                    unAuthorized(request, response);
                } else {
                    log.info("{} auth success", appCode);
                }
                return res;
            }
        }
        return false;
    }

    /**
     * 方法限流校验处理
     *
     * @param limitMethod
     * @return
     */
    private boolean checkLimit(Limit limitMethod) {
        String requestMethod = limitMethod.requestMethod();
        int count = limitMethod.count();
        long allowTime = limitMethod.allowTime();
        return SlideWindowLimitUtils.checkLimit(requestMethod, count, allowTime);
    }


    /**
     * Controller逻辑和视图解析器执行完毕
     *
     * @return
     * @author nari-yzg
     * @date 2021/3/30 10:48
     */
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        log.info("afterCompletion....");
    }

    private void setHttpResponse(HttpServletResponse response, String data) throws IOException {
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json; charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write(data);
    }

    private void unAuthorized(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String error = JSONObject.toJSONString(R.fail(HttpCodeEnum.UNPROCESABLE_ENTITY.getCode(),HttpCodeEnum.UNPROCESABLE_ENTITY.getMessage()));
        log.error("request uri = {} auth fail and get platform info fail", request.getRequestURI());
        this.setHttpResponse(response, error);
    }


}
